﻿using System.Collections.Generic;
using System.Diagnostics.Eventing.Reader;
using Abp.Extensions;
using Abp.Json;
using Abp.UI;
using Castle.MicroKernel.Registration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using pandx.Mulan.Extensions;

namespace pandx.Mulan.Flows
{
    public class FlowRuntime
    {
        public Dictionary<string, FlowNode> Nodes { get; set; }
        public List<FlowLine> Lines { get; set; }
        public Dictionary<string, List<FlowLine>> FromLines { get; set; }
        public Dictionary<string, List<FlowLine>> ToLines { get; set; }

        public string Name { get; set; }
        
        public FlowNode StartNode { get; set; }

        public FlowNode EndNode { get; set; }

        public FlowNode CurrentNode { get; set; }
        

        public FlowNode NextNode { get; set; }

      
        public FlowNode PrevNode { get; set; }

     
        public long InstanceId { get; set; }
        public string InstanceName { get; set; }
        public string FormData { get; set; }

        public FlowRuntime(FlowInstance instance)
        {
            dynamic schemeContentJson = instance.FlowSchemeContent.JsonToObject();
            Name = schemeContentJson.name;
            InitNodes(schemeContentJson);
            InitLines(schemeContentJson);

            FormData = instance.FormData;
            var currentNodeId = "";
            if (instance.State == FlowInstanceState.Draft && !instance.RejectNodeId.IsNullOrWhiteSpace())
            {
                currentNodeId = instance.RejectNodeId;
            }
            else
            {
                currentNodeId=instance.ActivityNodeId.IsNullOrWhiteSpace() ? StartNode.Id : instance.ActivityNodeId;
            }
            CurrentNode = Nodes[currentNodeId];
            PrevNode = instance.PrevNodeId.IsNullOrWhiteSpace()?null:Nodes[instance.PrevNodeId];
            InstanceId = instance.Id;
            InstanceName = instance.Name;
            if (CurrentNode.Type == FlowNode.End)
            {
                NextNode = null;
            }
            else
            {
                var nextNodeId = GetNextNodeId();
                NextNode = Nodes[nextNodeId];
            }
        }
        
      
        public string GetNextNodeId(string nodeId=null)
        {
        
            var lines = nodeId == null ? FromLines[CurrentNode.Id] : FromLines[nodeId];
            if (lines.Count == 0)
            {
                throw new UserFriendlyException("无法找到下一个节点");
            }
            if (FormData.IsNullOrWhiteSpace())
            {
                return lines[0].To;
            }
            
            var formData = FormData.ToLower().JsonToJObject();
            foreach (var line in lines)
            {
                if (line.Conditions.Count != 0 && line.Compare(formData))
                {
                    return line.To;
                }
            }

            return lines[0].To;
        }
        

        private void InitNodes(dynamic schemeContent)
        {
            Nodes = new Dictionary<string, FlowNode>();
            foreach (JObject item in schemeContent.nodeList)
            {
                var node = item.ToObject<FlowNode>();
                if (!Nodes.ContainsKey(node.Id))
                {
                    Nodes.Add(node.Id, node);
                }

                if (node.Type == FlowNode.Start)
                {
                    StartNode = node;
                }

                if (node.Type == FlowNode.End)
                {
                    EndNode = node;
                }
            }
        }

        private void InitLines(dynamic schemeContent)
        {
            Lines = new List<FlowLine>();
            FromLines = new Dictionary<string, List<FlowLine>>();
            ToLines = new Dictionary<string, List<FlowLine>>();

            foreach (JObject item in schemeContent.lineList)
            {
                var line = item.ToObject<FlowLine>();
                var conditions = new List<Condition>();
                foreach (var condition in line.Conditions)
                {
                    conditions.Add(condition);
                }
                
                foreach (var condition in conditions)
                {
                    if (condition.Field.IsNullOrWhiteSpace() || condition.Operation.IsNullOrWhiteSpace() ||
                        condition.Value.IsNullOrWhiteSpace())
                    {
                        line.Conditions.Remove(condition);
                    }
                }

                Lines.Add(line);

                if (!FromLines.ContainsKey(line.From))
                {
                    var ls = new List<FlowLine> {line};
                    FromLines.Add(line.From, ls);
                }
                else
                {
                    FromLines[line.From].Add(line);
                }

                if (!ToLines.ContainsKey(line.To))
                {
                    var ls = new List<FlowLine> {line};
                    ToLines.Add(line.To, ls);
                }
                else
                {
                    ToLines[line.To].Add(line);
                }
            }
        }
        
        
    }
}
